package com.ibatis4J.framework.dal.resource.parse;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;

import com.ibatis4J.framework.dal.exception.DalException;

/**
 * SQL模板解析器
 * 
 * @author liuwenya
 *
 */
public class XmlParser {
	
	/**日志*/
	private static Logger logger=LoggerFactory.getLogger(XmlParser.class);
	
	/**XML解析器*/
	private static XmlParser parser=new XmlParser();
	
	/**解析SqlMap后的结果*/
	private Map<String,SqlBean> sqlMapResult=new HashMap<String,SqlBean>();
	
	/**
	 * 构造方法私有化
	 */
	private XmlParser(){
		
	}
	
	/**
     * 获取XML解析器实例
     * 
     * @return XML解析器实例
     */
    public static XmlParser getInstance() {
        return parser;
    }
	
	/**
	 * SQL解析
	 * @param resources  资源
	 * @param sqlContainer  SQL容器
	 */
	public synchronized void parser(Resource[] resources,Map<String,SqlBean> sqlContainer){
		parserDocuments(createDocuments(resources));
		sqlContainer.putAll(sqlMapResult);
	}

	/**
	 * 解析XML文档，填充到Map
	 * @param resources  待解析资源
	 * @return  生成的Map对象,该对象以资源名为key,以Document为value
	 */
	private Map<String, Document> createDocuments(Resource[] resources) {
		/**生成的Map对象，该对象以资源名为key,以Document为value*/
		Map<String,Document> documents=new HashMap<String,Document>();
		
		/**实例化SAX解析器*/
		if(resources!=null && resources.length > 0){
			SAXReader saxReader=new SAXReader();
			for (Resource resource : resources) {
				try {
					/**资源名*/
					String fileName=resource.getFilename();
					InputStream reader=resource.getInputStream();
					/**读取XML文件,获得document对象*/
					Document doc=saxReader.read(reader);
					documents.put(fileName, doc);
				} catch (Exception e) {
					logger.debug("SAXReader parse sqlMap xml error!");
					throw new DalException("error.dal.003", "SAXReader parse sqlMap xml error!", e);
				}
			}
		}
		return documents;
		
	}
	
	/**
	 * 解析XML文档类型的SQL文档集
	 * @param documents 填充后的Map集合
	 */
	private void parserDocuments(Map<String, Document> documents) {
		try {
			Iterator<Map.Entry<String, Document>> it=documents.entrySet().iterator();
			/**迭代解析SqlMap*/
			while(it.hasNext()){
				Map.Entry<String, Document> entry=it.next();
				logger.debug("Loadding sqlMap.xml :" + entry.getKey());
				parserDocument(entry.getKey(),entry.getValue().getRootElement());
			}
		} catch (Exception e) {
			throw new DalException("error.dal.003", "SAXReader parse sqlMap xml error!", e);
		}
		
	}

	/**
	 * 解析SQL文件
	 * @param fileName  待解析文件名
	 * @param rootElement  待解析文件的根节点
	 */
	private void parserDocument(String fileName, Element rootElement) {
		if(rootElement!=null){
			 String namespace = rootElement.attributeValue("namespace");
	            String rootIsRead = rootElement.attributeValue("isRead");
	            String rootDsName = rootElement.attributeValue("dsName");           
	            String rootDbType = rootElement.attributeValue("dbType");
	            
	            if (namespace == null || "".equals(namespace)) {
	                logger.debug("SqlMap Element must have namespace : " + fileName);
	                throw new DalException("error.dal.003", "SqlMap Element must have namespace : " + fileName);
	            }
	            List<Element> sqlElements = rootElement.elements();
	            /** 循环遍历节点，解析SqlMap */
	            for (Element element : sqlElements) {
	                /** 读取ID */
	                String id = element.attributeValue("id");
	                /** 读取可读属性 */
	                String isRead = element.attributeValue("isRead");
	                /** 读取数据源名称 */
	                String dsName = element.attributeValue("dsName");
	                
	                String dbType= element.attributeValue("dbType");
	                
	                
	                /** 判断为空时的处理逻辑 */
	                if (isRead == null || "".equals(isRead)) {
	                    isRead = rootIsRead;
	                }
	                if (dsName == null || "".equals(dsName)) {
	                    dsName = rootDsName;
	                }
	                if (dbType == null || "".equals(dbType)) {
	                	dbType = rootDbType;
	                }
	                
	                if (id == null || "".equals(id)) {
	                    logger.debug("Sql Element must have id : " + fileName);
	                    throw new DalException("error.dal.004", "Sql Element must have id : " + fileName);
	                }
	                /** 读取SQL语句内容 */
	                String sql = element.getTextTrim();
	                sqlMapResult.put(appendSqlId(namespace, id), new SqlBean(id, isRead, sql, dsName, dbType));
	            }
		}
		
	}

	/**
	 * namespace和SqlId连接成字符串
	 * @param namespace  命名空间
	 * @param id  SqlId
	 * @return  拼接后的编号全称(namespace+"."+SqlId)
	 */
	private String appendSqlId(String namespace, String id) {
		return new StringBuffer().append(namespace).append(".").append(id).toString();
	}
}
